﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace EpiMapit
{
    class CurveUrlGenerator
    {
        public CurveUrlGenerator()
        {
        }

        public static string GetCurveChartUrl(int width, int height, IEnumerable<CaseSet> caseSets, string type, out int numberOfDateValue)
        {
            SortedDictionary<DateTime, int> dateValues = CurveUrlGenerator.getDateValuesForType(caseSets, type);

            numberOfDateValue = dateValues.Count;

            var urlformat = "http://chart.apis.google.com/chart?cht=lxy&chs={0}x{1}&chm=s,00FF00,0,-1,5|s,0000FF,1,-1,5&chdl=Per day|Accumulated&chco=00FF00,0000FF&chd=t:";

            string result;

            if (numberOfDateValue > 0)
            {
                var firstDate = dateValues.First().Key;
                var lastDate = dateValues.Last().Key;
                var difference = (lastDate - firstDate).TotalSeconds;

                //the first date will have a x axis value of 0, the rest will have the difference in time with the first one
                var resultBuilder = dateValues.Skip(1).Aggregate(
                    new StringBuilder().AppendFormat(urlformat, width, height).Append(difference == 0 ? 50 : 0),
                    (sb, item) => sb.AppendFormat(",{0:0.##}", difference == 0 ? 50 : (item.Key - firstDate).TotalSeconds * 100 / difference));

                resultBuilder.Append("|");

                //the y axis values for each date in the not accumulated
                var resultData = dateValues.Skip(1).Aggregate(
                     resultBuilder.Append(dateValues.First().Value),
                     (sb, item) => sb.AppendFormat(",{0}", item.Value));

                resultData.Append("|");

                //I repeat the x axis values for the accumulated
                resultData = dateValues.Skip(1).Aggregate(
                    resultData.Append(difference == 0 ? 50 : 0),
                    (sb, item) => sb.AppendFormat(",{0:0.##}", difference == 0 ? 50 : (item.Key - firstDate).TotalSeconds * 100 / difference));

                resultData.Append("|");

                //I build the accumulated values for y axis
                var accumulated = dateValues.First().Value;
                resultData.Append(accumulated); //first value
                //then I iterate over the rest
                foreach (var curVar in dateValues.Values.Skip(1))
                {
                    accumulated += curVar;
                    resultData.AppendFormat(",{0}", accumulated);
                }

                //I add the axis indicators
                resultData.Append("&chxt=y,x&chxl=1:");

                resultData.AppendFormat("|{0}|{1}", firstDate.ToShortDateString(), lastDate.ToShortDateString());

                //I add the grid
                resultData.Append("&chg=100,20");

                //I adjust the accumulated to be a 25 multiple
                if(accumulated % 25 != 0)
                    accumulated += 25 - (accumulated % 25);

                //I scale the y axis values
                resultData.AppendFormat("&chds=0,100,0,{0},0,100,0,{0}", accumulated);

                //And I adjust the y axis indicators accordingly to new scale
                resultData.AppendFormat("&chxr=0,0,{0},{1}", accumulated, accumulated / 5);

                result = resultData.ToString();
            }
            else
            {
                result = new StringBuilder().AppendFormat(urlformat, width, height).ToString();
            }

            if (result.Contains("10695"))
            {
                Debugger.Break();
            }

            return result;
        }

        //gets a dictionary from a list of caseSets, filtering only the cases that match the type, and ordering by date
        private static SortedDictionary<DateTime, int> getDateValuesForType(IEnumerable<CaseSet> caseSets, string type)
        {
            SortedDictionary<DateTime, int> returnValues = new SortedDictionary<DateTime, int>();
            foreach (var caseSet in caseSets)
            {
                if (type == null)
                    {
                    int value;
                    if (returnValues.TryGetValue(caseSet.Date, out value))
                    {
                        returnValues[caseSet.Date] += caseSet.Levels.Values.Sum();
                    }
                    else
                    {
                        returnValues.Add(caseSet.Date, caseSet.Levels.Values.Sum());
                    }
                    continue;
                }

                foreach (var keyValue in caseSet.Levels)
                {
                    if (keyValue.Key == type)
                    {
                        returnValues.Add(caseSet.Date, keyValue.Value);
                    }
                }
            }
            return returnValues;
        }
    }
}
